//
// Created by lingzhitech on 25-10-10.
//

#include "Message.hpp"
#include <iostream>

/**
 * 将message保存到folder中
 * @param f
 */
void Message::save(Folder &f) {
    folders.insert(&f); // add the given Folder to our list of Folders
    f.addMessage(this); // add this Message to f's set of Messages
}

/**
 * 将message从某个folder中删除
 * @param f
 */
void Message::remove(Folder &f) {
    folders.erase(&f); // take the given Folder out of our list of Folders
    f.removeMessage(this); // remove this Message to f's set of Messages
}

void Message::addMessageToFolders() {
    for (auto f: folders) // for each Folder that holds m
        f->addMessage(this); // add a pointer to this Message to that Folder
}

Message::Message(const Message &m): contents(m.contents), folders(m.folders) {
    addMessageToFolders(); // add this Message to the Folders that point to m
}

/**
 * 根据message所在的folders删除当前message的指针,并且清空folders
 */
void Message::removeMessageFromFolders() {
    for (auto f: folders) // for each pointer in folders
        f->removeMessage(this); // remove this Message from that Folder
    folders.clear(); // no Folder points to this Message
}

Message::~Message()
{
    removeMessageFromFolders();
}

Message& Message::operator=(const Message &rhs)
{
    if (this == &rhs)
        return *this;  // 避免自赋值破坏关系
    removeMessageFromFolders(); // update existing Folders
    contents = rhs.contents; // copy message contents from rhs
    folders = rhs.folders; // copy Folder pointers from rhs
    addMessageToFolders(); // add this Message to those Folders
    return *this;
}

Message::Message(Message &&message): contents(std::move(message.contents)) {
    moveFolders(&message);
}

Message& Message::operator=(Message &&rhs)
{
    if (this != &rhs) { // direct check for self-assignment
        removeMessageFromFolders();
        contents = std::move(rhs.contents); // move assignment
        moveFolders(&rhs); // reset the Folders to point to this Message
    }
    return *this;
}
void swap(Message &lhs, Message &rhs)
{
    using std::swap; // not strictly needed in this case, but good habit
    // remove pointers to each Message from their (original) respective Folders
    for (auto f: lhs.folders)
        f->removeMessage(&lhs);
    for (auto f: rhs.folders)
        f->removeMessage(&rhs);
    // swap the contents and Folder pointer sets
    swap(lhs.folders, rhs.folders); // uses swap(set&, set&)
    swap(lhs.contents, rhs.contents); // swap(string&, string&)
    // add pointers to each Message to their (new) respective Folders
    for (auto f: lhs.folders)
        f->addMessage(&lhs);
    for (auto f: rhs.folders)
        f->addMessage(&rhs);
}


std::ostream& operator<<(std::ostream& os, const Message& message) {
    os << "Message@" << &message << ": " << message.contents;
    os << " ||| Folders: ";
    for (auto f: message.folders)
        os << "Folder@" << f << " | ";
    return os;
}

void Message::addFolder(Folder *f) {
    folders.insert(f);
}

void Message::removeFolder(Folder *f) {
    folders.erase(f);
}

void Message::moveFolders(Message* m) {
    folders = std::move(m->folders); // uses set move assignment
    for (auto f : folders) { // for each Folder
        f->removeMessage(m); // remove the old Message from the Folder
        f->addMessage(this); // add this Message to that Folder
    }
    m->folders.clear(); // ensure that destroying m is harmless
}